/*************************************************************************
 *
 *  Copyright (C) 2013 Florian Dang <florian.coin@gmail.com>
 *
 *  This file is part of NatusVerse.
 *
 *  NatusVerse is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  NatusVerse is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with NatusVerse.  If not, see <http://www.gnu.org/licenses/>.
 *
 *************************************************************************/

#ifndef INC_LIGHTTRACER_SCENE_H_
#define INC_LIGHTTRACER_SCENE_H_

/*!
 * \file        scene.h
 * \brief       3D raytracing scene
 * \author      Florian Dang
 * \date        2013
 */

#include <stdio.h>
#include <vector>

#include "raytracer/objects/light.h"
#include "raytracer/objects/ray.h"
#include "raytracer/objects/object.h"
#include "raytracer/objects/camera.h"

namespace raytracer
{
//! Raytracer scene
/*!
  Objects, lights, camera...
*/
class Scene
{
	public:
		typedef std::vector<Object *> VecObject; // pointer here
		typedef std::vector<Light> VecLight;

		//! default scene constructor
		Scene() : vec_object_(), vec_light_(), camera_() {}
		//! classic scene constructor
		Scene(VecObject vec_object0, VecLight vec_light0, Camera camera0)
			: vec_object_(vec_object0), vec_light_(vec_light0), camera_(camera0),
			 num_objects_(vec_object0.size()), num_lights_(vec_light0.size()){}

		//! destructor
		~Scene() {}

		void VecCopy(const VecObject& vec_ref, VecObject& vec_dest)
		{
			for(int i = 0; i < static_cast<int>(vec_ref.size()); i ++)
			{
				vec_dest[i] = (vec_ref[i])->clone();
				printf("copy %d", i);
			}
		}

		//! objects array accessor
		inline const VecObject& vec_object() const { return vec_object_; }
		//! lights array accessor
		inline const VecLight& vec_light() const { return vec_light_; }
		//! camera accessor
		inline const Camera& camera() const { return camera_; }
		//! numobjects accessor
		inline const int& num_objects() const { return num_objects_; }
		//! numlights accessor
		inline const int& num_lights() const { return num_lights_; }

		//! camera mutator
		inline void set_camera(Camera camera0) { camera_ = camera0; }
		inline void set_num_objects() { num_objects_ = static_cast<int>(vec_object().size()); }
		inline void set_num_lights() { num_lights_ = static_cast<int>(vec_light().size()); }

		static Scene TestScene1(int w, int h);
		static Scene TestScene2(int w, int h);

		//! add specific object to the scene
		void AddObject(Object* object);

		//! add specific light to the scene
		void AddLight(Light light);

		//! add specific light to the scene
		bool RemoveLight(int index);

		void MoveLightX(int index, float begin, float end, float& sign);

		void MoveObject(size_t idx, float dx, float dy, float dz)
		{
			vec_object_[idx]->Move(dx, dy, dz);
		}

		//! Nearest object regarding a specific view light
		void NearestObject(const Ray& ray_view, Object*& nearest_object, float& nearest_t) const;

		bool IsInShadow(const Ray& ray_light) const;

		//! I/O informations about Scene
		void Print() const;

	private:
		// careful cannot instanciate directly abstract class without pointer use
		VecObject vec_object_; /*!< spheres, planes... */
		VecLight  vec_light_;  /*!< light */
		Camera    camera_;     /*!< camera or observer */

		int       num_objects_;
		int       num_lights_;
};
}
#endif  // INC_LIGHTTRACER_SCENE_H_
